package org.zxp.thread.lock;

import org.junit.Test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @program: zxp-thread-test
 * @description:  读写锁测试类
 * @author: X-Pacific zhang
 * @create: 2019-05-14 20:43
 **/
public class ReentrantReadWriteLockTest {
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    Lock r = lock.readLock();
    Lock w = lock.writeLock();

    public static void main(String[] args) {
        ReentrantReadWriteLockTest test = new ReentrantReadWriteLockTest();
//        for (int i = 0; i < 3; i++) {
//            new Thread(() -> {
//                r.inCreate();//写
//                r.print();//读 从读的角度，第一个线程读时
//            }).start();
//        }
        for (int i = 0; i < 200; i++) {
            if(i == 100){
                test.get2();
            }else {
                new Thread(() -> {
                    test.scroll();
                }).start();
            }
        }
    }

    public int num = 0;

    //读操作，读时不能写 读时可以读
    public int get() {
        r.lock();
        try {
            for (int k = 0; k < 10; k++) {
                System.out.println(num);
            }
            return num;
        } finally {
            r.unlock();
        }
    }

    //不加锁，读时可能不可重复读~~即读出的内容不一样
    public int get2() {
        try {
            for (int k = 0; k < 10; k++) {
                System.out.println(num);
            }
            return num;
        } finally {
        }
    }

    //写操作，写时不能写也不能读
    public void scroll() {
        w.lock();
        try {
            num++;
        } finally {
            w.unlock();
        }
    }

    @Test
    public void testDowngrade(){
        //单个线程 读-读 不互斥
        r.lock();
        r.lock();
        System.out.println("读-读 不互斥");
        r.unlock();
        r.unlock();
        //多个线程 读-读 不互斥
        new Thread(() -> {
            r.lock();
            try {Thread.sleep(2000L);} catch (InterruptedException e) {}
            r.unlock();
        }).start();
        new Thread(() -> {
            r.lock();
            System.out.println("立刻执行");
            r.unlock();
        }).start();
        //单个线程 读-写 互斥，不存在锁升级
        r.lock();
        w.lock();
        System.out.println("ok");
        w.unlock();
        r.unlock();
        //单个线程 写-读 不互斥，降级
        w.lock();
        r.lock();
        System.out.println("ok");
        r.unlock();
        w.unlock();
        //多个线程 写-读 互斥
        new Thread(() -> {
            w.lock();
            try {Thread.sleep(10000000L);} catch (InterruptedException e) {}
            w.unlock();
        }).start();
        try {Thread.sleep(500L);} catch (InterruptedException e) {}//等第一个线程
        new Thread(() -> {
            r.lock();
            System.out.println("我能获得读锁");
            r.unlock();
        }).start();
        //降级后，其他线程读不能进来 因为写锁并没有完全释放，其实就是为了线程内写读转化的处理用的
        new Thread(() -> {
            w.lock();
            r.lock();
            System.out.println("我已经降级了");
            try {Thread.sleep(2000L);} catch (InterruptedException e) {}
            r.unlock();
            w.unlock();
        }).start();
        new Thread(() -> {
            r.lock();
            System.out.println("我能进去");
            r.unlock();
        }).start();
        System.out.println("这是正确的写法");
        new Thread(() -> {
            w.lock();
            r.lock();
            w.unlock();
            System.out.println("我已经降级了");
            try {Thread.sleep(2000L);} catch (InterruptedException e) {}
            r.unlock();
        }).start();
        new Thread(() -> {
            r.lock();
            System.out.println("我能进去");
            r.unlock();
        }).start();

        try {Thread.sleep(10000L);} catch (InterruptedException e) {}
    }
}
